//***************************************************************************//
//*
//* 内容摘要：Vander编码处理
//*	
//* 当前版本：V1.0		
//* 作    者：zhfayuan
//* 完成日期：2016-8-21
//**************************************************************************//
#ifndef CSDVAND_ENC_H
#define CSDVAND_ENC_H

#include "SDVandermonde.h"
#include "SDPacketBuffer.h"

typedef enum 
{
    VANDERMONDEENC_OK =  0, 
    VANDERMONDEENC_ERR = 4000,
    VANDERMONDEENC_NOT_INITED,
    VANDERMONDEENC_ID_INVALID,
    VANDERMONDEENC_IS_IDLE,
    VANDERMONDEENC_ID_ISFULL,
    VANDERMONDEENC_INVALID_POINTOR,
    VANDERMONDEENC_MALLOC_FAILED,
    VANDERMONDEENC_BUFFER_NOT_ENOUGH,
    VANDERMONDEENC_REDUNT_IS_ZERO,
    VANDERMONDEENC_SET_PARAM_FAILED,
}E_VANDERMODE_ENC_ERROR_CODE;

typedef enum 
{
    VANDERMONDE_ENC_IDLE,
    VANDERMONDE_ENC_IN_USED
}E_VANDERMONDE_ENC_STATUS;

typedef struct _t_vandermondeenc
{
    UINT8 uStatus;
    UINT8 uRedundancy;
    UINT16 uiPacketMaxLen;
    T_VANDER_MONDE *pEncHdl;
    

    UINT32 uiEncTimes;
    UINT32 uiEncErr;
    UINT32 uiEncBufNotEnough;
}T_VanderMondeEnc; 

#define GF_BITS  8  /* code over GF(2**GF_BITS)*/
#define GF_SIZE ((1 << GF_BITS) - 1)    /* powers of \alpha */

#define FEC_2K_SIZE                	1024*2
#define PRE_ALLOC_SIZE 			   	1

/*
 * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
 * faster to use a multiplication table.
 *
 * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
 * many numbers by the same constant. In this case the first
 * call sets the constant, and others perform the multiplications.
 * A value related to the multiplication is held in a local variable
 * declared with USE_GF_MULC . See usage in addmul1().
 */

#define gf_mul(x,y) gf_mul_table[x][y]

#define USE_GF_MULC register gf * __gf_mulc_
#define GF_MULC0(c) (__gf_mulc_ = gf_mul_table[(c)])
#define GF_ADDMULC(dst, x) ((dst) ^= __gf_mulc_[(x)])

class CSDVanderEnc
{
public:
	CSDVanderEnc()
	{
		VanderEnc_CreateNew();
	}
	~CSDVanderEnc()
	{
		VanderEnc_Destroy();
	}
	
	INT32 vandermondeenc_setparam(UINT32 eFecParamType, void *value);
	INT32  vandermondeenc_getparam(UINT32 eFecParamType, void *value);	
	INT32 vandermonde_encode(T_FEC_DATA *pIn, T_FEC_DATA *pOut, void *pEncParam);	
	static T_PacketBuffer *GetFecPacketBuf(int nDataBufSize);	
	static void FreeFecPacketBuf(T_PacketBuffer *pPacketBuffer);	
private:

	T_VanderMondeEnc *pVanderEnc;
	gf  gf_exp[2*GF_SIZE];   /* index->poly form conversion table    */
	int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table    */
	gf  inverse[GF_SIZE+1];  /* inverse of field elem.               */
                             /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */	
	const char *allPp[17];
	gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];	
	//add for preprocess
	unsigned char *g_encmatrix;
	//end
	unsigned char g_auGroupSize[11];
	unsigned char g_uSupportGroupSizeNum;	
	
	
	int invert_vdm(gf *src, int k);
	void VanderEnc_CreateNew(void);
	void VanderEnc_Destroy(void);
	void init_static_var(void);
	
	T_VANDER_MONDE * vander_monde_new(void);
	void vander_monde_free(T_VANDER_MONDE *p);	
	
	bool init_vandermonde(void);
	void uninit_vandermonde(void);	
	
	void generate_gf(void);	
	void init_mul_table(void);	
	gf modnn(int x);
	bool initEncMatrix(void);
	void matmul(gf *a, gf *b, gf *c, int n, int k, int m);	
	void addmul(BYTE *dst1, BYTE *src1, BYTE c, int sz);
	//void *my_malloc(int sz, char *err_string);	
	//void my_free(void *p);	
	int vander_monde_encode(T_VANDER_MONDE *code, T_FEC_DATA *src, T_FEC_DATA *parity, int k, int n, int sz);	
	int vander_monde_set_param(T_VANDER_MONDE *code, int k, int n);	
	
};
#endif
